package blockchain

import (
	"context"
	"fmt"
	"math/big"
	"strings"
	"time"

	"private-domain-overseas-service/admin/business/api/internal/repository/blockchain"
	"private-domain-overseas-service/admin/business/api/internal/svc"
	apitypes "private-domain-overseas-service/admin/business/api/internal/types"
	"private-domain-overseas-service/pkg/constant"
	"private-domain-overseas-service/pkg/status/bizblockchain"
	"private-domain-overseas-service/tools/ent/hzblockchainwalletrecord"
	"private-domain-overseas-service/tools/ent/predicate"

	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	ethtypes "github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/core/logx"
)

type BlockchainWalletTransferLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// 后台提币转账
func NewBlockchainWalletTransferLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BlockchainWalletTransferLogic {
	return &BlockchainWalletTransferLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

// 构造转账数据
func (l *BlockchainWalletTransferLogic) constructTransferData(toAddress common.Address, amount *big.Int) ([]byte, error) {
	// ERC-20 transfer方法的ABI
	transferABI := constant.HzbABI

	// 解析ABI
	parsedABI, err := abi.JSON(strings.NewReader(transferABI))
	if err != nil {
		logx.Errorf("解析ABI失败%v", err)
	}

	// 构造调用数据
	data, err := parsedABI.Pack("transfer", toAddress, amount)
	if err != nil {
		logx.Errorf("构造调用数据失败%v", err)
	}

	return data, nil
}

func (l *BlockchainWalletTransferLogic) BlockchainWalletTransfer(req *apitypes.BlockchainWalletTransferRequest) (resp *apitypes.BlockchainWalletTransferResponse, err error) {
	// 参数验证
	if req.RecordID <= 0 {
		return nil, errors.New("无效的记录ID")
	}

	logx.Infof("开始处理转账请求,记录ID:%d", req.RecordID)

	// 获取区块链钱包记录DAO
	blockchainWalletRecordDao := blockchain.NewBlockchainWalletRecordDao(l.ctx, l.svcCtx)

	// 查询记录
	records, _, err := blockchainWalletRecordDao.GetBlockchainWalletRecords([]predicate.HzBlockchainWalletRecord{
		hzblockchainwalletrecord.IDEQ(int(req.RecordID)),
	}, 1, 1)
	if err != nil {
		logx.Errorf("查询区块链钱包记录失败,记录ID:%d,错误:%v", req.RecordID, err)
		return nil, err
	}
	if len(records) == 0 {
		logx.Errorf("记录不存在.记录ID:%d", req.RecordID)
		return nil, err
	}
	record := records[0]

	// 根据记录中的wallet_id获取钱包地址
	wallet, err := blockchain.NewBlockchainWalletDao(l.ctx, l.svcCtx).GetWalletByID(record.BlockchainWalletID)
	if err != nil {
		logx.Errorf("查询钱包地址失败,钱包ID:%d,错误：%v", record.BlockchainWalletID, err)
		return nil, errors.Wrap(err, "查询钱包地址失败")
	}
	if wallet == nil {
		logx.Errorf("钱包地址不存在,钱包ID:%d", record.BlockchainWalletID)
		return nil, err
	}

	// 检查记录状态
	if record.RecordStatus != bizblockchain.DoneStatus {
		return nil, fmt.Errorf("记录状态不正确，当前状态：%d,期望状态:%d", record.RecordStatus, bizblockchain.DoneStatus)
	}

	// 检查转账状态
	if record.RecordTransferStatus != bizblockchain.TransferProcessing {
		return nil, fmt.Errorf("转账状态不正确，当前状态：%d,期望状态:%d", record.RecordTransferStatus, bizblockchain.TransferProcessing)
	}

	// 连接到zkSync节点
	logx.Infof("正在连接RPC节点: %s", l.svcCtx.Config.Blockchain.GethRpcURLs)
	client, err := ethclient.Dial(l.svcCtx.Config.Blockchain.GethRpcURLs[0])
	if err != nil {
		logx.Errorf("连接zkSync节点失败,错误:%v", err)
		return nil, errors.Wrap(err, "连接zkSync节点失败")
	}
	defer client.Close()

	// 获取发送方私钥
	privateKey, err := crypto.HexToECDSA(l.svcCtx.Config.Blockchain.BackendPrivateKey)
	if err != nil {
		logx.Errorf("解析私钥失败，错误：%v", err)
		return nil, errors.Wrap(err, "解析私钥失败")
	}

	// 获取发送方地址
	fromAddress := crypto.PubkeyToAddress(privateKey.PublicKey)
	logx.Infof("发送方地址: %s", fromAddress.Hex())

	// 获取接收方地址
	toAddress := common.HexToAddress(wallet.WalletAddress) // 使用 RecordTitle 作为接收地址
	logx.Infof("接收方地址: %s", toAddress.Hex())

	// 获取代币合约地址
	tokenAddress := common.HexToAddress(l.svcCtx.Config.Blockchain.HzbContract)
	logx.Infof("代币合约地址: %s", tokenAddress.Hex())

	// 获取nonce
	nonce, err := client.PendingNonceAt(l.ctx, fromAddress)
	if err != nil {
		logx.Errorf("获取nonce失败,错误:%v", err)
		return nil, errors.Wrap(err, "获取nonce失败")
	}

	// 获取gas价格
	gasPrice, err := client.SuggestGasPrice(l.ctx)
	if err != nil {
		logx.Errorf("获取gas价格失败,错误:%v", err)
		return nil, errors.Wrap(err, "获取gas价格失败")
	}

	// 构造转账数据
	// 将金额转换为最小单位（例如：如果 1 HZB = 100 最小单位）
	amount := big.NewInt(record.RecordHzbCoin * 100)
	data, err := l.constructTransferData(toAddress, amount)
	if err != nil {
		logx.Errorf("构造转账数据失败,错误：%v", err)
		return nil, errors.Wrap(err, "构造转账数据失败")
	}

	// 估算gas limit
	gasLimit, err := client.EstimateGas(l.ctx, ethereum.CallMsg{
		From:  fromAddress,
		To:    &tokenAddress,
		Data:  data,
		Value: big.NewInt(0),
	})
	if err != nil {
		logx.Errorf("估算gas limit失败,错误：%v", err)
		return nil, errors.Wrap(err, "估算gas limit失败")
	}
	// 增加20%的buffer
	gasLimit = gasLimit * 120 / 100
	logx.Infof("估算的gas limit: %d", gasLimit)

	// 计算手续费（使用 GasPriceRate）
	gasFee := new(big.Int).Mul(gasPrice, big.NewInt(int64(gasLimit)))
	gasFeeHzb := new(big.Int).Mul(gasFee, big.NewInt(int64(constant.GasPriceRate*100)))
	gasFeeHzb = gasFeeHzb.Div(gasFeeHzb, big.NewInt(100))
	logx.Infof("估算的gas费用: %s HZB", gasFeeHzb.String())

	// 构造交易
	tx := ethtypes.NewTransaction(nonce, tokenAddress, big.NewInt(0), gasLimit, gasPrice, data)

	// 签名交易
	chainID, err := client.NetworkID(l.ctx)
	if err != nil {
		logx.Errorf("获取链ID失败,错误:%v", err)
		return nil, errors.Wrap(err, "获取链ID失败")
	}

	signedTx, err := ethtypes.SignTx(tx, ethtypes.NewEIP155Signer(chainID), privateKey)
	if err != nil {
		logx.Errorf("签名交易失败,错误：%v", err)
		return nil, errors.Wrap(err, "签名交易失败")
	}

	// 发送交易
	logx.Infof("正在发送交易,交易哈希：%s", signedTx.Hash().Hex())
	err = client.SendTransaction(l.ctx, signedTx)
	if err != nil {
		logx.Errorf("发送交易失败,错误：%v", err)
		return nil, errors.Wrap(err, "发送交易失败")
	}

	// 等待交易确认
	logx.Infof("等待交易确认,交易哈希：%s", signedTx.Hash().Hex())
	receipt, err := client.TransactionReceipt(l.ctx, signedTx.Hash())
	if err != nil {
		logx.Errorf("获取交易收据失败,错误：%v", err)
		return nil, errors.Wrap(err, "获取交易收据失败")
	}

	if receipt.Status == 0 {
		logx.Errorf("交易失败，交易哈希：%s", signedTx.Hash().Hex())
		return nil, errors.New("交易失败")
	}

	logx.Infof("交易成功，交易哈希：%s", signedTx.Hash().Hex())

	// 更新记录状态
	record.RecordTransferStatus = bizblockchain.TransferSuccess
	record.RecordTransferCompleteTime = time.Now().Unix()
	record.RecordHash = signedTx.Hash().Hex()

	// 更新记录
	updateTime := time.Now().Unix()
	record.UpdateAt = updateTime
	_, err = l.svcCtx.Orm.HzBlockchainWalletRecord.UpdateOne(record).
		SetRecordTransferStatus(record.RecordTransferStatus).
		SetRecordTransferCompleteTime(record.RecordTransferCompleteTime).
		SetRecordHash(record.RecordHash).
		SetUpdateAt(updateTime).
		Save(l.ctx)
	if err != nil {
		logx.Errorf("更新记录失败，错误：%v", err)
		return nil, errors.Wrap(err, "更新记录失败")
	}

	return &apitypes.BlockchainWalletTransferResponse{
		Success: true,
		Message: fmt.Sprintf("转账成功，交易哈希：%s", signedTx.Hash().Hex()),
	}, nil
}
